﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Demo.Framework.Datastructure.Dictionary
{
    class Program
    {
        /*
         * 1. Sort a Collection - use IComparer<T>, object - IComparable
         * 2. Union a Collection - USing IEqualityComparer
         * 3. Last N items in a list
         * /
         */
        static void Main(string[] args)
        {
            try
            {                                
                List<Dividend> reutersdividends = new List<Dividend>()
                {
                    new Dividend(){ExDate = new DateTime(2013,12,31),Amount=1,Id=1,Type="Regular", StockId = 1},
                    new Dividend(){ExDate = new DateTime(2015,12,31),Amount=2.3,Id=2,Type="Regular", StockId = 2},
                    new Dividend(){ExDate = new DateTime(2017,12,31),Amount=3.9,Id=3,Type="Regular", StockId = 3},
                    new Dividend(){ExDate = new DateTime(2014,12,31),Amount=4.5,Id=4,Type="Special", StockId = 1},
                    new Dividend(){ExDate = new DateTime(2013,12,31),Amount=1,Id=5,Type="Interim", StockId = 1},
                };

                List<Dividend> bloombergdividends = new List<Dividend>()
                {
                    new Dividend(){ExDate = new DateTime(2013,12,31),Amount=99.9,Id=1,Type="Regular", StockId = 1},
                    new Dividend(){ExDate = new DateTime(2015,12,31),Amount=98.9,Id=2,Type="Regular", StockId = 2},
                    new Dividend(){ExDate = new DateTime(2017,12,31),Amount=3.9,Id=3,Type="Regular", StockId = 9},
                    new Dividend(){ExDate = new DateTime(2014,12,31),Amount=4.5,Id=4,Type="Special", StockId = 10},
                    new Dividend(){ExDate = new DateTime(2013,12,31),Amount=1,Id=5,Type="Interim", StockId = 11},
                };
                
                // Sorting of a Collection   

                Console.WriteLine("Dividends before sorting");
                PrintDividends(reutersdividends);

                // Sorting Dividends - by ExDate, Stock

                reutersdividends.Sort(new DividendComparer());
                Console.WriteLine("Dividends after sorting");
                PrintDividends(reutersdividends);

                Console.WriteLine("Dividend Equality Test");

                // Adding duplicate in a dictionary - The Iequalitycomparer allows us to test for equality between two objects
                var d1 = new Dividend(){ExDate = new DateTime(2013,12,31),Amount=1.9 ,Id=1,Type="Regular", StockId = 1};
                var d2 = new Dividend(){ExDate = new DateTime(2013,12,31),Amount=2.9 ,Id=4,Type="Regular", StockId = 1};
                var d3 = new Dividend(){ExDate = new DateTime(2013,12,31),Amount=3.9 ,Id=2,Type="Special", StockId = 1};
                var d4 = new Dividend(){ExDate = new DateTime(2014,12,31),Amount=3.9 ,Id=3,Type="Special", StockId = 1};

                Dictionary<Dividend, int> divDictionary = new Dictionary<Dividend, int>(new DividendEqualityComparer());
                divDictionary[d1] = d1.Id;
                divDictionary[d2] = d2.Id;
                divDictionary[d3] = d3.Id;
                divDictionary[d4] = d4.Id;

                PrintDividends(divDictionary.Keys.ToList());

                Console.WriteLine("Union of two collections");
                // Union of two collections - remove duplicates
                var divList = reutersdividends.Union(bloombergdividends, new DividendEqualityComparer()).ToList();
                PrintDividends(divList);

                Console.WriteLine("Intersect of two collections");
                divList = reutersdividends.Intersect(bloombergdividends, new DividendEqualityComparer()).ToList();
                PrintDividends(divList);

                // Search a collection
                Console.WriteLine("Search dividends with Id 1");
                divList = reutersdividends.FindAll(d => d.StockId == 1);
                PrintDividends(divList);

                // Last N items in a list

                Console.WriteLine("Select last N records from a collection");
                int count = reutersdividends.Count;
                var coll = reutersdividends.Select((d) => d).Skip(count - 3).Take(3).ToList();
                PrintDividends(coll);

                // Difference between OrderBy and Sort 
                // Sort reorders an existing list, OrderBy gives back a new list

                // Test for equality
                var c1 = new MyEqualityTestClass() { Property = "P1" };
                var c2 = new MyEqualityTestClass() { Property = "P1" };

                Console.Write("Equals :{0}", c1.Equals(c2));

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                Console.Read();
            }
        }

        static void PrintDividends(List<Dividend> dividends)
        {
            dividends.ForEach((d) =>
            {
                Console.WriteLine("Dividend - ExDate: {0}, Id: {1}, Type: {2}, Amount: {3}, Stock: {4}",
                    d.ExDate.ToString("yyyy-MMM-dd"), d.Id, d.Type, d.Amount, d.StockId);
            });
        }
    }

    public class Dividend:IComparable
    {
    
        public DateTime ExDate { get; set; }
        public int Id { get; set; }
        public double Amount { get; set; }
        public string Type { get; set; }
        public int StockId { get; set; }

        public int CompareTo(object obj)
        {
            Dividend otherDividend = (Dividend) obj;

            if (this.ExDate.CompareTo(otherDividend.ExDate) !=0)
            {
                return this.ExDate.CompareTo(otherDividend.ExDate);
            }
            else
            {
                return this.StockId.CompareTo(otherDividend.StockId);
            }

        }

        public override int GetHashCode()
        {
            return (ExDate.GetHashCode() ^ Type.GetHashCode() ^ StockId.GetHashCode());
        }
    }

    public class DividendComparer:IComparer<Dividend>
    {
        public int Compare(Dividend x, Dividend y)
        {
            return x.CompareTo(y);
        }
    }

    public class DividendEqualityComparer : IEqualityComparer<Dividend>
    {

        public bool Equals(Dividend x, Dividend y)
        {
            return x.StockId == y.StockId && x.ExDate == y.ExDate && x.Type == y.Type;
        }

        public int GetHashCode(Dividend obj)
        {
            return obj.GetHashCode();
        }
    }

    class MyEqualityTestClass
    {
        public string Property { get; set; }
        public override bool Equals(object obj)
        {
            return ((MyEqualityTestClass)obj).Property == this.Property;
        }
    }
}
